﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace System.DbSizeForecaster
{
    public static class DbFieldSizeProvider
    {
        /// <summary>
        ///     Gets the number of bytes reserved for a well known sql server data type.
        /// </summary>
        /// <param name="dataType">The data type, e.g. int, smalldatetime etc.</param>
        /// <param name="precision">The precision of the data type.</param>
        /// <param name="scale">The scale of the data type.</param>
        /// <returns>
        ///     The average number of bytes for a given data type.
        /// </returns>
        /// <exception cref="NotSupportedException">
        ///     Raised if the given data type is unknown.
        /// </exception>
        public static double GetFieldBytes(string dataType, int precision = 1, int scale = 1, int length = 1)
        {
            if (string.IsNullOrWhiteSpace(dataType))
                throw new ArgumentNullException("dataType");

            dataType = dataType.Trim().ToLower();

            switch (dataType)
            {
                case "int":
                    return 4;
                case "uniqueidentifier":
                    return 16;
                case "smallint":
                    return 2;
                case "tinyint":
                    return 1;
                case "money":
                    return 8;
                case "smallmoney":
                case "smalldatetime":
                    return 4;
                case "xml":
                    return length;//uncertain how to calculate xml data
                case "float":
                    return 6;//average of 4 or 8
                case "datetime":
                    return 8;
                case "datetime2":
                    return 6;//between 4 and 8
                case "binary":
                    return 1;
                case "nvarchar":
                case "nchar":
                    return (2 * precision) + 2;
                case "varchar":
                case "char":
                    return precision + 2;
                case "bigint":
                    return 8;
                case "image":
                case "varbinary":
                    return precision + 2;
                case "decimal":
                case "numeric":
                    {
                        if (scale + precision < 9)
                            return 5;
                        else if (scale + precision < 19)
                            return 9;
                        else if (scale + precision < 28)
                            return 13;
                        else
                            return 17;
                    }
                case "bit":
                    return 0.1;
                default:
                    throw new NotSupportedException(string.Format("The data type {0} is not supported.", dataType));
            }
        }
    }
}
